#include "screen.h"


Screen TheScreen;
HFONT Screen::hfont;


Screen::Screen()
{
	ATOM wndcls;
	WNDCLASSEX clsex;
	HBRUSH hbrush;
	LOGBRUSH logbrush;

	logbrush.lbColor = RGB(0,0,0);
	logbrush.lbStyle = BS_SOLID;
	logbrush.lbHatch = 0;
	hbrush = CreateBrushIndirect(&logbrush);
	if (hbrush == NULL) {
		LogFatal("failed to create brush");
	}

	clsex.cbSize = sizeof(WNDCLASSEX);
	clsex.cbClsExtra = 0;
	clsex.cbWndExtra = 0;
	clsex.style = CS_DBLCLKS | CS_NOCLOSE;
	clsex.hbrBackground = hbrush;
	clsex.hIcon = NULL;
	clsex.hIconSm = NULL;
	clsex.hCursor = LoadCursor(NULL, IDC_ARROW);
	clsex.hInstance = NULL;
	clsex.lpszClassName = L"hellokitty";
	clsex.lpszMenuName = NULL;
	clsex.lpfnWndProc = WndProc;
	
	wndcls = RegisterClassEx(&clsex);
	if (wndcls == 0) {
		LogFatal("failed to register window class");
	}

	hwnd = CreateWindow(
		(LPCWSTR)wndcls, 
		L"Crowbar Monitor", 
		WS_CAPTION | WS_MINIMIZEBOX,
		100, 
		100, 
		800 + GetSystemMetrics(SM_CXSIZEFRAME) * 2, 
		600 + GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CYSIZEFRAME) * 2, 
		NULL, 
		NULL, 
		NULL, 
		NULL
	);
	if (hwnd == NULL) {
		LogFatal("failed to create window");
	}

	hfont = CreateFont(
		0,
		10,
		0,
		0,
		FW_NORMAL,
		FALSE,
		FALSE,
		FALSE,
		ANSI_CHARSET,
		OUT_DEFAULT_PRECIS,
		CLIP_DEFAULT_PRECIS,
		DEFAULT_QUALITY,
		FIXED_PITCH | FF_MODERN,
		L"Fixedsys"
	);
	if (hfont == NULL) {
		LogFatal("failed to create font");
	}

	m_cursor_col = 0;
	m_cursor_row = 0;
	memset(m_text_rows, 32, COLUMNS*ROWS);

	ShowWindow(hwnd, SW_SHOW);
}

LRESULT CALLBACK Screen::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	int wmId, wmEvent;
	PAINTSTRUCT ps;
	HDC hdc;
	int y;
	
	switch (message)
	{
	case WM_PAINT:
		hdc = BeginPaint(hWnd, &ps);
		SetTextColor(hdc, RGB(0,255,0));
		SetBkMode(hdc, TRANSPARENT);
		SelectObject(hdc, hfont);
		SetTextCharacterExtra(hdc, 2);
		
		for (y=0; y<ROWS; y++) {
			TextOutA(hdc, 0, y*15, (LPCSTR)TheScreen.m_text_rows[y], COLUMNS);
		}
		EndPaint(hWnd, &ps);
		break;
	case WM_KEYDOWN:
		if (wParam == VK_RETURN) {
			TheScreen.Print(" \r\n");
		}
		else if (wParam == VK_ESCAPE) {
			Scheduler.Stop();
		}
		else if (wParam == VK_SPACE) {
			TheScreen.Print(" ");
		}
		else if (wParam == VK_BACK) {
			TheScreen.Print(" \b\b");
		}
		else if (wParam == VK_TAB) {
			TheScreen.Print("    ");
		}
		else if (wParam >= 0x30 && wParam <= 0x5a) {
			char ch[2];
			ch[0] = (char)wParam;
			ch[1] = 0;
			TheScreen.Print(ch);
		}
		TheScreen.Print("_\b");
		break;
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	default:
		return DefWindowProc(hWnd, message, wParam, lParam);
	}
	return 0;
}

void Screen::PutChar(char ch) 
{
	switch (ch) 
	{
	case '\b':
		m_cursor_col--;
		break;
	case '\n':
		m_cursor_row++;
		break;
	case '\r':
		m_cursor_col = 0;
		break;
	default:
		if (ch < 32 || ch > 126) {
			ch = ' ';
		}
		m_text_rows[m_cursor_row][m_cursor_col] = ch;
		m_cursor_col++;
		break;
	}
	
	if (m_cursor_col < 0) {
		m_cursor_col = COLUMNS-1;
		m_cursor_row--;
	}
	else if (m_cursor_col >= COLUMNS) {
		m_cursor_col = 0;
		m_cursor_row++;
	}

	if (m_cursor_row < 0) {
		m_cursor_row = 0;
	}
	else if (m_cursor_row >= ROWS) {
		memcpy(&m_text_rows[0], &m_text_rows[1], COLUMNS * (ROWS-1));
		memset(&m_text_rows[ROWS-1], ' ', COLUMNS);
		m_cursor_col = 0;
		m_cursor_row = ROWS-1;
	}
}

void Screen::Print(const char * text)
{
	char *ch;
	for(ch = (char*)text; *ch != 0; ch++) {
		PutChar(*ch);
	}
	InvalidateRect(hwnd, NULL, TRUE);
}

